package wafa.criterion;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.joda.time.DateMidnight;

public class Restriction {

	public static Criterion or(final Criterion condition1,
			final Criterion condition2) {

		StringBuilder concatenation = new StringBuilder();
		concatenation.append("(");
		concatenation.append(condition1.getCriterion());
		concatenation.append(" OR ");
		concatenation.append(condition2.getCriterion());
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion and(final Criterion condition1,
			final Criterion condition2) {

		StringBuilder concatenation = new StringBuilder();
		concatenation.append("(");
		concatenation.append(condition1.getCriterion());
		concatenation.append(" AND ");
		concatenation.append(condition2.getCriterion());
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion equal(final String key, final Object value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" = ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else {
			concatenation.append(value);
		}

		return new Criterion(concatenation.toString());
	}

	public static Criterion deferens(final String key, final Object value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" != ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else {
			concatenation.append(value);
		}

		return new Criterion(concatenation.toString());
	}

	// great than
	public static Criterion greatThan(final String key, final Object value) {

		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" > ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else {
			concatenation.append(value);
		}
		return new Criterion(concatenation.toString());
	}

	public static Criterion greaterThanOrEqual(final String key,
			final Object value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" >= ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else {
			concatenation.append(value);
		}
		return new Criterion(concatenation.toString());
	}

	public static Criterion lessThan(final String key, final Object value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" < ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else {
			concatenation.append(value);
		}

		return new Criterion(concatenation.toString());
	}

	public static Criterion lessThanOrEqual(final String key, final Object value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" <= ");
		if (value.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value));
		} else if (value.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value)));
		} else if (value.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value)
							.toDate())));
		} else {
			concatenation.append(value);
		}

		return new Criterion(concatenation.toString());
	}

	public static Criterion isNull(final String key) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" IS NULL ");
		return new Criterion(concatenation.toString());
	}

	public static Criterion isNotNull(final String key) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" IS NOT NULL ");
		return new Criterion(concatenation.toString());
	}

	public static Criterion in(final String key, final List<Object> listValue) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" IN (");
		if (listValue.get(0).getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) listValue.get(0)));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation.append(addDoublePrime((String) listValue.get(i)));
			}

		} else if (listValue.get(0).getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) listValue
					.get(0))));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation
						.append(addDoublePrime(getFormatDate((Date) listValue
								.get(i))));
			}
		} else if (listValue.get(0).getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) listValue
							.get(0)).toDate())));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation
						.append(addDoublePrime(getFormatDate(((DateMidnight) listValue
								.get(i)).toDate())));
			}
		} else {
			concatenation.append(listValue.get(0));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation.append(listValue.get(i));
			}
		}
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion notIn(final String key, final List<Object> listValue) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" NOT IN (");
		if (listValue.get(0).getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) listValue.get(0)));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation.append(addDoublePrime((String) listValue.get(i)));
			}

		} else if (listValue.get(0).getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) listValue
					.get(0))));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation
						.append(addDoublePrime(getFormatDate((Date) listValue
								.get(i))));
			}
		} else if (listValue.get(0).getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) listValue
							.get(0)).toDate())));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation
						.append(addDoublePrime(getFormatDate(((DateMidnight) listValue
								.get(i)).toDate())));
			}
		} else {
			concatenation.append(listValue.get(0));
			for (int i = 1; i < listValue.size(); i++) {
				concatenation.append(", ");
				concatenation.append(listValue.get(i));
			}
		}
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion like(final String key, final String value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" LIKE ");
		concatenation.append(addDoublePrime(value));
		return new Criterion(concatenation.toString());
	}

	public static Criterion notLike(final String key, final String value) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("@");
		concatenation.append(key);
		concatenation.append(" NOT LIKE ");
		concatenation.append(addDoublePrime(value));
		return new Criterion(concatenation.toString());
	}

	private static String addDoublePrime(final String string) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("\"");
		concatenation.append(string);
		concatenation.append("\"");
		return concatenation.toString();

	}

	private static String getFormatDate(final Date date) {
		final SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd");
		return formater.format(date);
	}

	public static Criterion between(final String key, final Object value1,
			final Object value2) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("(@");
		concatenation.append(key);
		concatenation.append(" BETWEEN ");
		if (value1.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value1));
			concatenation.append(" AND ");
			concatenation.append(addDoublePrime((String) value2));
		} else if (value1.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value1)));
			concatenation.append(" AND ");
			concatenation.append(addDoublePrime(getFormatDate((Date) value2)));
		} else if (value1.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value1)
							.toDate())));
			concatenation.append(" AND ");
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value2)
							.toDate())));

		} else {
			concatenation.append(value1);
			concatenation.append(" AND ");
			concatenation.append(value2);
		}
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion notBetween(final String key, final Object value1,
			final Object value2) {
		StringBuilder concatenation = new StringBuilder();
		concatenation.append("(@");
		concatenation.append(key);
		concatenation.append(" NOT BETWEEN ");
		if (value1.getClass().isInstance("string")) {
			concatenation.append(addDoublePrime((String) value1));
			concatenation.append(" AND ");
			concatenation.append(addDoublePrime((String) value2));
		} else if (value1.getClass().isInstance(new Date())) {
			concatenation.append(addDoublePrime(getFormatDate((Date) value1)));
			concatenation.append(" AND ");
			concatenation.append(addDoublePrime(getFormatDate((Date) value2)));
		} else if (value1.getClass().isInstance(new DateMidnight())) {
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value1)
							.toDate())));
			concatenation.append(" AND ");
			concatenation
					.append(addDoublePrime(getFormatDate(((DateMidnight) value2)
							.toDate())));

		} else {
			concatenation.append(value1);
			concatenation.append(" AND ");
			concatenation.append(value2);
		}
		concatenation.append(")");
		return new Criterion(concatenation.toString());
	}

	public static Criterion allDocument() {
		return new Criterion("");
	}

}
